package vg.services.data_base_manager.data.header;

import vg.services.main_manager.MainManager;

public class AttributeHeader implements Cloneable {
	// Defines
	public static final int VERTEX_OWNER_TYPE = 1;
	public static final int EDGE_OWNER_TYPE = 2;
    public static final int GRAPH_OWNER_TYPE = 3;

    public static final int NO_ATTRIBUTE_TYPE = -1;
    public static final int STRING_ATTRIBUTE_TYPE = 1;
    public static final int BOOLEAN_ATTRIBUTE_TYPE = 2;
    public static final int INTEGER_ATTRIBUTE_TYPE = 3;
    public static final int DOUBLE_ATTRIBUTE_TYPE = 4;

	// Main data
	private int id;
    private int ownerId;
    private int ownerType;

    private String name = null;
	private Object value = null;
    private int type = NO_ATTRIBUTE_TYPE;

	private AttributeHeader(int id, int ownerId, int ownerType) {
        this.id = id;
		this.ownerId = ownerId;
		this.ownerType = ownerType;
	}

    public static AttributeHeader createVertexAttributeHeader(int id, int vertexId) {
        return new AttributeHeader(id, vertexId, VERTEX_OWNER_TYPE);
    }

    public static AttributeHeader createEdgeAttributeHeader(int id, int edgeId) {
        return new AttributeHeader(id, edgeId, EDGE_OWNER_TYPE);
    }

    public static AttributeHeader createGraphAttributeHeader(int id, int graphId) {
        return new AttributeHeader(id, graphId, GRAPH_OWNER_TYPE);
    }

    public int getId() {
        return id;
    }

    public int getOwnerId() {
        return ownerId;
    }

    public int getOwnerType() {
        return ownerType;
    }

    public String getName() {
        return name;
    }

    public int getType() {
        return type;
    }

    /**
     * Returns string value, if type is string, otherwise <b>null</b>
     */
    public String getStringValue() {
        if (type == STRING_ATTRIBUTE_TYPE)
            return (String)value;
        return null;
    }

    /**
     * Returns integer value, if type is integer, otherwise <b>null</b>
     */
    public Integer getIntegerValue() {
        if (type == INTEGER_ATTRIBUTE_TYPE)
            return (Integer)value;
        return null;
    }

    /**
     * Returns boolean value, if type is boolean, otherwise <b>null</b>
     */
    public Boolean getBooleanValue() {
        if (type == BOOLEAN_ATTRIBUTE_TYPE)
            return (Boolean)value;
        return null;
    }

    /**
     * Returns double value, if type is double, otherwise <b>null</b>
     */
    public Double getDoubleValue() {
        if (type == DOUBLE_ATTRIBUTE_TYPE)
            return (Double)value;
        return null;
    }

    /**
     * Returns double value, if type is real, otherwise <b>null</b>
     */
    public Double getRealValue() {
        if (isIntegerType())
            return ((Integer)value).doubleValue();

        if (isDoubleType())
            return (Double)value;

        return null;
    }


    public boolean isStringType() {
        return getType() == STRING_ATTRIBUTE_TYPE;
    }

    public boolean isBooleanType() {
        return getType() == BOOLEAN_ATTRIBUTE_TYPE;
    }

    public boolean isIntegerType() {
        return getType() == INTEGER_ATTRIBUTE_TYPE;
    }

    public boolean isDoubleType() {
        return getType() == DOUBLE_ATTRIBUTE_TYPE;
    }

    public boolean isRealType() {
        return isDoubleType() || isIntegerType();
    }

    public boolean isNullType() {
        return getType() == NO_ATTRIBUTE_TYPE;
    }

    public void setName(String name) {
        if (name == null)
            throw new RuntimeException("Name can't be null");

        this.name = name;
    }

    public boolean setStringValue(String value) {
        if (value == null)
            return false;

        type = STRING_ATTRIBUTE_TYPE;
        this.value = value;
        return true;
    }

    public boolean setBooleanValue(Boolean value) {
        if (value == null)
            return false;

        type = BOOLEAN_ATTRIBUTE_TYPE;
        this.value = value;
        return true;
    }

    public boolean setIntegerValue(Integer value) {
        if (value == null)
            return false;

        type = INTEGER_ATTRIBUTE_TYPE;
        this.value = value;
        return true;
    }

    public boolean setDoubleValue(Double value) {
        if (value == null)
            return false;

        type = DOUBLE_ATTRIBUTE_TYPE;
        this.value = value;
        return true;
    }

    public boolean setValue(String value, int type) {
        try {
            switch (type) {
                case AttributeHeader.BOOLEAN_ATTRIBUTE_TYPE:
                    return setBooleanValue(Boolean.valueOf(value));

                case AttributeHeader.DOUBLE_ATTRIBUTE_TYPE:
                    return setDoubleValue(Double.valueOf(value));

                case AttributeHeader.INTEGER_ATTRIBUTE_TYPE:
                    return setIntegerValue(Integer.valueOf(value));

                case AttributeHeader.STRING_ATTRIBUTE_TYPE:
                    return setStringValue(String.valueOf(value));

                default:
                    return false;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    /**
     * Returns string value.
     */
    public String toStringValue() {
        if (value == null)
            return null;
        return value.toString();
    }

    /**
     * Returns string value.
     * If value equals null then returns empty string.
     */
    public String toNotNullStringValue() {
        if (value == null)
            return "";
        return value.toString();
    }

    @Override
	public AttributeHeader clone() {
		AttributeHeader a = new AttributeHeader(id, ownerId, ownerType);
		a.name = name;
		a.value = value;
		a.type = type;
		return a;
	}

    public static boolean isTypeAvailable(int type) {
        switch (type) {
            case AttributeHeader.BOOLEAN_ATTRIBUTE_TYPE:
            case AttributeHeader.DOUBLE_ATTRIBUTE_TYPE:
            case AttributeHeader.INTEGER_ATTRIBUTE_TYPE:
            case AttributeHeader.STRING_ATTRIBUTE_TYPE:
                return true;
            default:
                return false;
        }
    }

    public static boolean isRealType(int type) {
        return (type == INTEGER_ATTRIBUTE_TYPE || type == DOUBLE_ATTRIBUTE_TYPE);
    }
}
